#include "Source.h"
#include "View3D.h"
#include "View2D.h"
#include "DisplayModel.h"
#include "DisplayFramework.h"
#include "PipelineModel.h"

#include "vtkHyperStreamline.h"
#include "vtkPropCollection.h"
#include "vtkRenderedAreaPicker.h"
#include "vtkDataSetMapper.h"
#include "vtkPolyDataMapper.h"
#include "vtkContourFilter.h"
#include "vtkProperty.h"
#include "vtkDataset.h"
#include "vtkPointData.h"
#include "vtkCellData.h"
#include "vtkSphereRepresentation.h"
#include "vtkRegularPolygonSource.h"
#include "vtkSphereWidget2.h"
#include "vtkCylinderSource.h"
#include "vtkCellArray.h"
#include "vtkTubeFilter.h"
#include "vtkAxesActor.h"
#include "vtkMath.h"

#include <QList>
#include <QVector4D>
#include <QTest>

DisplayModel::DisplayModel() : QObject()
{
	m_realTimeSource=NULL;
	m_rtView=NULL;
	m_extractor=NULL;
	m_cuttingView=NULL;
	m_selectedMapper=NULL;
	m_selectedActor=NULL;
	m_displayFramework = NULL;
	qMemSet(&m_rtsSpacing, 3, sizeof(double));
	m_listSphereSource.clear();
	m_listSphereActor.clear();
	m_listSphereMapper.clear();
	m_listSpherePosition.clear();
	m_listBranchInfo.clear();
	m_selectedIndex = -1;
}


DisplayModel::~DisplayModel()
{

}


/************************************************************************/
/* 1. get active view
	 2. get propers in view, now just get 3d actors
	 3. extract data set
	 4. add selected proper to active view
	 */
/************************************************************************/
void DisplayModel::slotStartCutting()
{
	m_cuttingView = m_displayFramework->getActive3DView();
	QList<vtkProp*>* propers = m_cuttingView->getProperList();
	if ( propers->size() == 0)
	{
		m_cuttingView = NULL;
		return;
	}

	vtkRenderedAreaPicker *picker = m_cuttingView->getPicker();

	m_cuttingView->switchMode(dmPicking);
	
	m_extractor = vtkExtractSelectedFrustum::New();
	m_selectedActor = vtkActor::New();


	QList<vtkProp*>::iterator it = propers->begin();
	for ( ; it != propers->end(); it++ )
	{
		if ( (*it)->IsA("vtkActor"))
		{
			vtkActor *actor = (vtkActor *)(*it);

			double *bounds = actor->GetBounds();

			std::cout << *bounds << ", " << *(bounds+1) << ", " << *(bounds+2) 
				<< ", " << *(bounds+3) << ", " << *(bounds+4) << ", " << *(bounds+5) << std::endl;

			m_extractor->AddInput(actor->GetMapper()->GetInput());
			
		}
	}

	m_extractor->SetFrustum(picker->GetFrustum());

	m_selectedMapper = vtkDataSetMapper::New();
	m_selectedMapper->SetInput(vtkDataSet::SafeDownCast(m_extractor->GetOutput()));
	
	m_selectedActor->SetMapper(m_selectedMapper);

	m_cuttingView->addProper(m_selectedActor);
}


void DisplayModel::slotStopCutting()
{
	if ( m_extractor)
	{
		m_extractor->Delete(); 
		m_extractor = NULL;
	}

	if ( m_cuttingView)
	{
		m_cuttingView->switchMode(dmNormal);
		m_cuttingView->removeProper(m_selectedActor); 
		m_cuttingView=NULL;
	}
	
	if ( m_selectedMapper)
	{
		m_selectedMapper->Delete(); 
		m_selectedMapper=NULL;
	}

	if (m_selectedActor)
	{
		m_selectedActor->Delete(); 
		m_selectedActor=NULL;
	}
}


void DisplayModel::slotDoCut()
{
	if ( m_extractor)
	{


		return;
	}
}


void DisplayModel::slotDisplayOutline( const QModelIndex& index, bool flag/*=true*/ )
{
	Source *source = m_pipelineModel->sourceFromIndex(index);
	if ( !source)
		return;

	vtkActor *actor = source->outlineActor();
	if ( !actor)
		return;

	if ( flag == true)
		m_displayFramework->getActive3DView()->addProper(actor);
	else
		m_displayFramework->getActive3DView()->removeProper(actor);

	m_displayFramework->getActive3DView()->update();
}


void DisplayModel::slotDisplayModel( const QModelIndex& index, bool flag/*=true*/ )
{
	Source *source = m_pipelineModel->sourceFromIndex(index);
	if ( !source)
		return;

	vtkProp *actor = source->sourceModel();
	if ( !actor)
		return;

	if ( flag == true)
		m_displayFramework->getActive3DView()->addProper(actor);
	else
		m_displayFramework->getActive3DView()->removeProper(actor);

	m_displayFramework->getActive3DView()->update();
}


// void DisplayModel::slotDisplayVolume( const QModelIndex& index, bool flag/*=true*/ )
// {
// 	Source *source = m_pipelineModel->sourceFromIndex(index);
// 	if ( !source)
// 		return;
// 
// // 	vtkProp *actor = source->sourceModel();
// // 
// // 	if ( flag == true)
// // 		m_displayFramework->getActive3DView()->addProper(volume);
// // 	else
// // 		m_displayFramework->getActive3DView()->removeProper(volume);
// // 
// // 	m_displayFramework->getActive3DView()->update();
// }


void DisplayModel::setDisplayFramework(DisplayFramework* df)
{
	m_displayFramework = df;

	connect(df, SIGNAL(emitSeedPicked()), SLOT(slotSeedPicked()));
	connect(df, SIGNAL(emitViewActivated(int)), SLOT(slotViewActivated(int)));
	connect(df, SIGNAL(emitStartCutting()), SLOT(slotStartCutting()));
	connect(df, SIGNAL(emitStopCutting()), SLOT(slotStopCutting()));
	connect(df, SIGNAL(emitDoCut()), SLOT(slotDoCut()));
}


void DisplayModel::setPipelineModel(PipelineModel* pm)
{
	m_pipelineModel = pm;

	connect(pm, SIGNAL(emitPropertyChanged(Source*, SourceProperty)),
		SLOT(slotPropertyChanged(Source*, SourceProperty)));
}


bool DisplayModel::isDisplayingModel(const QModelIndex& index)
{
	Source *source = m_pipelineModel->sourceFromIndex(index);
	if ( !source)
		return false;

	QList<vtkProp*>* propers = m_displayFramework->getActive3DView()->getProperList();

	QList<vtkProp*>::iterator it = propers->begin();
	for ( ; it != propers->end(); it++)
	{
		if (*it == source->sourceModel())
		{
			return true;
		}
	}

	return false;
}


bool DisplayModel::isDisplayingOutline(const QModelIndex& index)
{
	Source *source = m_pipelineModel->sourceFromIndex(index);
	if ( !source)
		return false;

	QList<vtkProp*>* propers = m_displayFramework->getActive3DView()->getProperList();

	QList<vtkProp*>::iterator it = propers->begin();
	for ( ; it != propers->end(); it++)
	{
		if (*it == source->outlineActor())
		{
			return true;
		}
	}

	return false;
}


// bool DisplayModel::isDisplayingVolume(const QModelIndex& index)
// {
// 	Source *source = m_pipelineModel->sourceFromIndex(index);
// 	if ( !source)
// 		return false;
// 
// // 	QList<vtkProp*>* propers = m_displayFramework->getActive3DView()->getProperList();
// // 
// // 	QList<vtkProp*>::iterator it = propers->begin();
// // 	for ( ; it != propers->end(); it++)
// // 	{
// // 		if (*it == source->sourceModel())
// // 		{
// // 			return true;
// // 		}
// // 	}
// 
// 	return false;
// }

void DisplayModel::slotPickSeed()
{
	if ( m_displayFramework->getActive2DView()->baseImage())
		m_displayFramework->getActive2DView()->pickSeed();
}

void DisplayModel::slotSeedSelected( QString seed)
{
	m_displayFramework->getActive2DView()->seedSelected(seed);
}


void DisplayModel::slotRemoveSeed( QString seed)
{
	m_displayFramework->getActive2DView()->removeSeed(seed);
}


void DisplayModel::slotStopRealTimeSlicing()
{
	m_realTimeSource->sourceModel(true);

	m_displayFramework->getActive3DView()->slotStopRealTimeSlicing();
	m_realTimeSource = NULL;
}

void DisplayModel::slotStartRealTimeSlicing( Source *source)
{
	m_realTimeSource = source;
	m_realTimeSource->data()->GetSpacing(m_rtsSpacing);

	m_rtView = m_displayFramework->getActive3DView();
	m_rtView->slotStartRealTimeSlicing();
}

void DisplayModel::slotUpdateRealTimeSlicing(vtkImageData* image, int num)
{
	image->SetOrigin(0,0,(double)num*m_rtsSpacing[2]);

	vtkContourFilter *filter = vtkContourFilter::New();
	filter->SetInput(image);
	filter->SetValue(0, 1);

	vtkPolyDataMapper *mapper = vtkPolyDataMapper::New();
	mapper->SetInputConnection(filter->GetOutputPort());

	vtkProperty *pro = vtkProperty::New();
	pro->SetColor(1,0,0);

	vtkActor *actor = vtkActor::New();
	actor->SetMapper(mapper);
	actor->SetProperty(pro);	
	
	m_rtView->updateRealTimeSlicing(actor);
}

bool DisplayModel::isDisplaying2D( const QModelIndex& index)
{
	Source *source = m_pipelineModel->sourceFromIndex(index);
	if ( !source)
		return false;


	QList<vtkImageData*> *images = m_displayFramework->getActive2DView()->imageList();

	QList<vtkImageData*>::iterator it = images->begin();
	for ( ; it != images->end(); it++)
	{
		if (*it == source->data())
		{
			return true;
		}
	}

	return false;
}

void DisplayModel::slotDisplay2DSlices( const QModelIndex& index, bool flag)
{
	Source *source = m_pipelineModel->sourceFromIndex(index);
	if ( !source)
		return;

// 	vtkImageData *image = source->data();
// 
// 	if ( flag == true)
// 		m_displayFramework->getActive2DView()->addProper(volume);
// 	else
// 		m_displayFramework->getActive2DView()->removeProper(volume);
// 
// 	m_displayFramework->getActive3DView()->update();
}

void DisplayModel::slotSetBaseSource( const QModelIndex& index)
{
	Source *source = m_pipelineModel->sourceFromIndex(index);
	if ( !source)
		return;

	vtkImageData *image = m_displayFramework->getActive2DView()->baseImage();

	// same one
	if ( image && image == source->data())
		return;

	m_displayFramework->getActive2DView()->setBaseImage(source->data());

}

void DisplayModel::thresholdChanged(Source *source)
{
	if ( !source || source->type()!=stVolume)
		return;

	vtkImageData *image = m_displayFramework->getActive2DView()->baseImage();
	VolumeSourceBase* vsource = (VolumeSourceBase*)source;
	
	if ( image == source->data())
		m_displayFramework->getActive2DView()->setBaseThreshold(vsource->getLowerThreshold(), vsource->getUpperThreshold());
}

void DisplayModel::slotPropertyChanged( Source* source, SourceProperty sp)
{
		switch (sp) 
		{
		case spDisplayOutline:
		case spDisplaySurface:
		case spDisplayVolume:
		case spSurfaceOpacity:
		case spRebuildSurface:
		case spPositionChanged:
			{
				m_displayFramework->getActive3DView()->render();

				break;
			}
		case spThreshold:
			{
				thresholdChanged(source);
				break;
			}
		case spBlending:
		case spVisibility:
		default:
			break;
		}
}

void DisplayModel::slotSeedPicked()
{
	emit emitUpdateSeeds(m_displayFramework->getActive2DView()->seedList());


	/*
	if ( m_displayFramework->getActive2DView()->viewMode() == vmPixelGear)
		{
			if ( !m_pgImage)
				return; 
	
	
			pg::FeatureDetector *detector = new pg::FeatureDetector(m_pgImage);
			pg::Point seed;
	
			int *s = currentSeedInt();
	
			seed.x = s[0];
			seed.y = s[1];
	
	
			if ( m_pgFDMethod == pg::gsCircle)
			{
				static int times = 1;
				static pg::Point pos[2];
	
				if ( times == 1) 
				{
					pos[0].x = s[0];
					pos[0].y = s[1];
	
					times++;
					return;
				}
				else if ( times == 2)
				{
					pos[1].x = s[0];
					pos[1].y = s[1];
					times = 1;
				}
	
	
				pg::Circle* circle = detector->detectCircle(pos[0], pos[1]);
	
				if ( circle)
				{
					cout << "Circle[" << circle->center.x << ", " << circle->center.y << ", " << circle->radius << "]" << endl;
	
					vtkRegularPolygonSource *circleSource = vtkRegularPolygonSource::New();
					circleSource->SetCenter(circle->center.x,circle->center.y,1);
					circleSource->SetRadius(circle->radius);
					circleSource->SetNumberOfSides(100);
					//circleSource->SetNormal(1,2,3);
	
					circleSource->GeneratePolylineOn();
					circleSource->GeneratePolygonOff();
	
					vtkPolyDataMapper *mapper = vtkPolyDataMapper::New();
					mapper->SetInputConnection(circleSource->GetOutputPort());
	
					vtkActor *actor = vtkActor::New();
					actor->SetMapper(mapper);
					actor->GetProperty()->SetColor(0,1,0);
					actor->GetProperty()->SetAmbient(1);
	
					m_displayFramework->getActive2DView()->getRenderer()->AddActor(actor);
				}
			}
			else if ( m_pgFDMethod == pg::gsLine)
			{
				pg::Line* line = detector->detectLine(seed);
	
				if ( line)
				{
					vtkLineSource *lineSource = vtkLineSource::New();
					lineSource->SetPoint1(line->start.x, line->start.y, 1);
					lineSource->SetPoint2(line->end.x, line->end.y, 1);
	
	
					vtkPolyDataMapper *mapper = vtkPolyDataMapper::New();
					mapper->SetInputConnection(lineSource->GetOutputPort());
	
					vtkActor *actor = vtkActor::New();
					actor->SetMapper(mapper);
					actor->GetProperty()->SetColor(0,1,0);
					actor->GetProperty()->SetAmbient(1);
	
					m_displayFramework->getActive2DView()->getRenderer()->AddActor(actor);
				}
				else
					printf("no line\n");
			}
		}*/
	
}

QString DisplayModel::currentSeed()
{
	return m_displayFramework->getActive2DView()->currentSeed();
}

int* DisplayModel::currentSeedInt()
{
	QStringList sl = m_displayFramework->getActive2DView()->currentSeed().split(",");

	int *seed = new int[3];

	seed[0] = sl.at(0).toInt();
	seed[1] = sl.at(1).toInt();
	seed[2] = sl.at(2).toInt();

	return seed;
}

void DisplayModel::slotViewActivated( int id)
{
	if ( id == 1 || id == 2)
	{
		emit emitUpdateSeeds(m_displayFramework->getActive2DView()->seedList());
	}
}

void DisplayModel::slotBlendImage( const QModelIndex& index, bool flag )
{
	Source *source = m_pipelineModel->sourceFromIndex(index);

	if ( !source)
		return;

	if ( flag == true)
		m_displayFramework->getActive2DView()->addBlendingImage(source->data());
	else
		m_displayFramework->getActive2DView()->removeBlendedImage(source->data());

}

vtkRenderWindowInteractor* DisplayModel::activeInteractor()
{
	return m_displayFramework->getActive3DView()->interactor();
}

void DisplayModel::getVisiblePropBounds(double *bounds)
{
	vtkRenderer *ren = m_displayFramework->getActive3DView()->getRenderer();
	if ( ren != NULL)
		ren->ComputeVisiblePropBounds(bounds);

	std::cout << "Bounds: " 
		<< bounds[0] << ", " 
		<< bounds[1] << ", "
		<< bounds[2] << ", "
		<< bounds[3] << ", "
		<< bounds[4] << ", "
		<< bounds[5] << std::endl;
}


bool DisplayModel::isSphereExisted(const QString& text)
{
	int iSphere = findSphere(text);

	return iSphere == -1?false:true;
}

bool DisplayModel::isASphere(vtkActor* actor)
{
	QList<vtkActor*>::Iterator it = m_listSphereActor.begin();
	for (; it != m_listSphereActor.end(); it++)
	{
		if ( actor == *it)
			return true;
	}

	return false;
}

bool DisplayModel::isALine(vtkActor* actor)
{
	QList<vtkActor*>::Iterator it = m_listLineActor.begin();
	for (; it != m_listLineActor.end(); it++)
	{
		if ( actor == *it)
			return true;
	}

	return false;
}

void DisplayModel::getLineProperty(vtkActor* actor, double start[3], double end[3])
{
	for (int i = 0; i < m_listLineActor.count(); i++)
	{
		if ( actor == m_listLineActor.at(i))
		{
			cout << "fount out line property" << endl;
			start[0]=m_listLinePosition.at(i)[0];
			start[1]=m_listLinePosition.at(i)[1];
			start[2]=m_listLinePosition.at(i)[2];
			end[0]=m_listLinePosition.at(i)[3];
			end[1]=m_listLinePosition.at(i)[4];
			end[2]=m_listLinePosition.at(i)[5];

			return;
		}
	}

	start[0] = 0; start[1] = 0; start[2] = 0;
	end[0] = 0; end[1] = 0; end[2] = 0;
}

void DisplayModel::addLine(double start[3],double end[3])
{
	addLine(start[0], start[1], start[2], end[0], end[1], end[2]);
}

void DisplayModel::addLine(double startx, double starty, double startz,
	double endx, double endy, double endz)
{
	vtkLineSource *line = vtkLineSource::New();
	line->SetPoint1(startx, starty, startz);
	line->SetPoint2(endx, endy, endz);
	line->SetResolution(20);
	line->Update();

// 	vtkCylinderSource *cs = vtkCylinderSource::New();
// 	cs->SetCenter((startx+endx)/2.0f, (starty+endy)/2.0f, (startz+endz)/2.0f);
// 	cs->SetHeight(sqrt)

	vtkPolyDataMapper* lineMapper = vtkPolyDataMapper::New();
	lineMapper->SetInputConnection(line->GetOutputPort());

	vtkActor *lineActor = vtkActor::New();
	lineActor->SetMapper(lineMapper);

	lineActor->GetProperty()->SetLineWidth(8);
	lineActor->GetProperty()->SetColor(170.0f/255.0f,1,0);

	m_displayFramework->getActive3DView()->getRenderer()->AddActor(lineActor);
	m_displayFramework->getActive3DView()->render();

	QList<double> pos; 
	pos.push_back(startx);
	pos.push_back(starty);
	pos.push_back(startz);
	pos.push_back(endx);  
	pos.push_back(endy);  
	pos.push_back(endz);

	m_listLinePosition.push_back(pos);
	m_listLineSource.push_back(line);
	m_listLineMapper.push_back(lineMapper);
	m_listLineActor.push_back(lineActor);
}


void DisplayModel::addLine(const QString& src, const QString& dst)
{
	QStringList sl_src = src.split(" ");
	QStringList sl_dst = dst.split(" ");

	if ( sl_src.size() != 4 || sl_dst.size() != 4)
		return;

	cout << "[DisplayModel] Ready to draw line" << endl;
	qDebug() << src;
	qDebug() << dst;

	double startx = sl_src[0].toDouble();
	double starty = sl_src[1].toDouble();
	double startz = sl_src[2].toDouble();

	double endx = sl_dst[0].toDouble();
	double endy = sl_dst[1].toDouble();
	double endz = sl_dst[2].toDouble();

	addLine(startx, starty, startz, endx, endy, endz);
}

void DisplayModel::addSphere(const QString& text)
{
	if ( text.isEmpty())
		return;

	QStringList sl = text.split(" ");
	if ( sl.size() != 4)
		return;

	double x = sl[0].toDouble();
	double y = sl[1].toDouble();
	double z = sl[2].toDouble();
	double r = sl[3].toDouble();

	addSphere(x,y,z,r);

// 	vtkSphereSource * sphere = vtkSphereSource::New();
// 	sphere->SetThetaResolution(32); 
// 	sphere->SetPhiResolution(32);
// 	sphere->SetRadius(r);
// 	sphere->SetCenter(x,y,z);
// 	sphere->Update();
// 
// 	vtkPolyDataMapper *sphereMapper = vtkPolyDataMapper::New();
// 	sphereMapper->SetInput(sphere->GetOutput());
// 	vtkActor *sphereActor = vtkActor::New();
// 	sphereActor->SetMapper(sphereMapper);
// 
// 	m_displayFramework->getActive3DView()->getRenderer()->AddActor(sphereActor);
// 	m_displayFramework->getActive3DView()->render();
// 
// 	m_listSpherePosition.push_back(text);
// 	m_listSphereSource.push_back(sphere);
// 	m_listSphereMapper.push_back(sphereMapper);
// 	m_listSphereActor.push_back(sphereActor);

// 	QString dst = QString("%1 %2 %3 %4").arg(x+50).arg(y+50).arg(z).arg(r);
// 	addLine(text, dst);
}

void DisplayModel::addSphere(double x, double y, double z, double r)
{
	vtkSphereSource * sphere = vtkSphereSource::New();
	sphere->SetThetaResolution(32); 
	sphere->SetPhiResolution(32);
	sphere->SetRadius(r);
	sphere->SetCenter(x,y,z);
	sphere->Update();

	vtkPolyDataMapper *sphereMapper = vtkPolyDataMapper::New();
	sphereMapper->SetInput(sphere->GetOutput());
	vtkActor *sphereActor = vtkActor::New();
	sphereActor->SetMapper(sphereMapper);

	m_displayFramework->getActive3DView()->getRenderer()->AddActor(sphereActor);
	m_displayFramework->getActive3DView()->render();

	QString text = QString("%1 %2 %3 %4").arg(x).arg(y).arg(z).arg(r);
	m_listSpherePosition.push_back(text);
	m_listSphereSource.push_back(sphere);
	m_listSphereMapper.push_back(sphereMapper);
	m_listSphereActor.push_back(sphereActor);
}


void DisplayModel::removeSphere( const QString& text )
{
	int iSphere = findSphere(text);

	if ( iSphere == -1)
	{
		std::cout << "Not find" << std::endl;
		return;
	}

	removeSphere(iSphere);
}

void DisplayModel::removeSphere(int i)
{
	if ( i < 0 || i >= m_listSphereSource.size() )
		return;

	printf("i=%d, size=%d\n", i, m_listSphereActor.size());

	vtkActor* actor = m_listSphereActor.at(i);
	vtkSphereSource* sphereSource = m_listSphereSource.at(i);
	vtkPolyDataMapper* polydataMapper = m_listSphereMapper.at(i);

	m_displayFramework->getActive3DView()->getRenderer()->RemoveActor(actor);

// 	polydataMapper->Delete();
// 	actor->Delete();


	m_listSpherePosition.removeAt(i);
	m_listSphereActor.removeAt(i);
	m_listSphereSource.removeAt(i);
	m_listSphereMapper.removeAt(i);

	m_displayFramework->getActive3DView()->render();
}

void DisplayModel::removeAllSpheres()
{
	int size = m_listSphereSource.size();

	for (int i =0; i < size; i++)
	{
		removeSphere(0);
	}
}

int DisplayModel::findSphere(const vtkActor* actor )
{
	int pos = 0;
	foreach(vtkActor* act, m_listSphereActor)
	{
		if ( actor == act)
			return pos;
		pos++;
	}

	return -1;
}

int DisplayModel::findSphere( const QString& text )
{
	int pos = 0;
	foreach(QString str, m_listSpherePosition)
	{
		if ( str == text)
			return pos;
		pos++;
	}

	return -1;
}

void DisplayModel::setSphereVisible( const QString& text, bool on )
{
	int i = findSphere(text);
	if ( i != -1)
	{
		vtkActor * actor = m_listSphereActor.at(i);

		if ( on == false)
			actor->VisibilityOff();
		else
			actor->VisibilityOn();
	}

	m_displayFramework->getActive3DView()->render();
}

void DisplayModel::setSphereRadiusRange( double from, double to )
{
	for (int i = 0; i < m_listSphereActor.size(); i++)
	{
		if ( m_listSphereSource.at(i)->GetRadius() < from || m_listSphereSource.at(i)->GetRadius() > to)
		{
			m_listSphereActor.at(i)->VisibilityOff();
		}
		else
			m_listSphereActor.at(i)->VisibilityOn();
	}

	m_displayFramework->getActive3DView()->render();
}

QString DisplayModel::getSpherePosition( vtkActor* actor )
{
	int i = findSphere(actor);
	if ( i != -1)
		return m_listSpherePosition.at(i);

	return QString("");
}


void DisplayModel::resetCamera()
{
	m_displayFramework->getActive3DView()->resetCamera();
}

void DisplayModel::updateActive3DScene()
{
	if ( m_displayFramework)
	{
		//m_displayFramework->getActive3DView()->update();
		m_displayFramework->getActive3DView()->render();
	}
}



void DisplayModel::addBranch(QList<QVector4D> pointlist, int nid, int bid)
{
	BranchInfo_t* branchInfo = new BranchInfo_t;

	vtkPoints* points = vtkPoints::New();
	vtkCellArray *line = vtkCellArray::New();
	vtkDoubleArray * tuberad = vtkDoubleArray::New();
	vtkUnsignedCharArray* normalColors = vtkUnsignedCharArray::New();
	vtkUnsignedCharArray* selectedColors0 = vtkUnsignedCharArray::New();
	vtkUnsignedCharArray* selectedColors1 = vtkUnsignedCharArray::New();	// add 5 more colors
	vtkUnsignedCharArray* selectedColors2 = vtkUnsignedCharArray::New();
	vtkUnsignedCharArray* selectedColors3 = vtkUnsignedCharArray::New();
	vtkUnsignedCharArray* selectedColors4 = vtkUnsignedCharArray::New();
	vtkUnsignedCharArray* selectedColors5 = vtkUnsignedCharArray::New();
	vtkUnsignedCharArray* selectedColors6 = vtkUnsignedCharArray::New();
	vtkUnsignedCharArray* selectedColors7 = vtkUnsignedCharArray::New();
	vtkUnsignedCharArray* selectedColors8 = vtkUnsignedCharArray::New();
	vtkUnsignedCharArray* selectedColors9 = vtkUnsignedCharArray::New();

	vtkPolyData *data = vtkPolyData::New();

	int samplerate = 4;
 	double maxradius = pointlist[0].w();
 	double minradius = pointlist[pointlist.count()-1].w();

	//m_listStartEnds.push_back(QPair<QVector4D,QVector4D>(pointlist[0],pointlist[pointlist.count()-1]));
	branchInfo->pairStartEnds = QPair<QVector4D,QVector4D>(pointlist[0],pointlist[pointlist.count()-1]);

	maxradius = maxradius*0.2+0.5;
	minradius = minradius*0.2+0.5;

	int samplenum = pointlist.count()/samplerate + 1;
	double dt = (maxradius - minradius)/(double)samplenum;

	tuberad->SetName("tuberad");
	tuberad->SetNumberOfTuples(samplenum);
	line->InsertNextCell(samplenum);

	normalColors->SetName("normalColors");
	normalColors->SetNumberOfComponents(3);
	normalColors->SetNumberOfTuples(samplenum);
	selectedColors0->SetName("selectedColors0");
	selectedColors0->SetNumberOfComponents(3);
	selectedColors0->SetNumberOfTuples(samplenum);
	selectedColors1->SetName("selectedColors1");
	selectedColors1->SetNumberOfComponents(3);
	selectedColors1->SetNumberOfTuples(samplenum);
	selectedColors2->SetName("selectedColors2");
	selectedColors2->SetNumberOfComponents(3);
	selectedColors2->SetNumberOfTuples(samplenum);
	selectedColors3->SetName("selectedColors3");
	selectedColors3->SetNumberOfComponents(3);
	selectedColors3->SetNumberOfTuples(samplenum);
	selectedColors4->SetName("selectedColors4");
	selectedColors4->SetNumberOfComponents(3);
	selectedColors4->SetNumberOfTuples(samplenum);
	selectedColors5->SetName("selectedColors5");
	selectedColors5->SetNumberOfComponents(3);
	selectedColors5->SetNumberOfTuples(samplenum);
	selectedColors6->SetName("selectedColors6");
	selectedColors6->SetNumberOfComponents(3);
	selectedColors6->SetNumberOfTuples(samplenum);
	selectedColors7->SetName("selectedColors7");
	selectedColors7->SetNumberOfComponents(3);
	selectedColors7->SetNumberOfTuples(samplenum);
	selectedColors8->SetName("selectedColors8");
	selectedColors8->SetNumberOfComponents(3);
	selectedColors8->SetNumberOfTuples(samplenum);
	selectedColors9->SetName("selectedColors9");
	selectedColors9->SetNumberOfComponents(3);
	selectedColors9->SetNumberOfTuples(samplenum);


	int i = 0;
	for (; i < pointlist.count()/samplerate; i++)
	{
		points->InsertPoint(i, pointlist[i*samplerate].x(), pointlist[i*samplerate].y(), pointlist[i*samplerate].z());
		line->InsertCellPoint(i);
		tuberad->SetTuple1(i, maxradius-dt*i);
		//colors->InsertTuple3(i, int(255*i/(samplenum-1)) , 0 , int(255*(samplenum-1-i)/(samplenum-1)) );
		normalColors->InsertTuple3(i, 0, 255, 0);
		selectedColors0->InsertTuple3(i, 255, 0, 0);
		selectedColors1->InsertTuple3(i, 0, 0, 255);
		selectedColors2->InsertTuple3(i, 170, 85, 255);
		selectedColors3->InsertTuple3(i, 170, 170, 255);
		selectedColors4->InsertTuple3(i, 170, 170, 0);
		selectedColors5->InsertTuple3(i, 255, 85, 255);
		selectedColors6->InsertTuple3(i, 85, 170, 255);
		selectedColors7->InsertTuple3(i, 85, 85, 255);
		selectedColors8->InsertTuple3(i, 255, 170, 0);
		selectedColors9->InsertTuple3(i, 255, 0, 127);
	}

	points->InsertPoint(i, pointlist[pointlist.count()-1].x(), 
			pointlist[pointlist.count()-1].y(), pointlist[pointlist.count()-1].z());
	line->InsertCellPoint(i);
	tuberad->SetTuple1(i, minradius);
	normalColors->InsertTuple3(i, 0, 255, 0);
	selectedColors0->InsertTuple3(i, 255, 0, 0);
	selectedColors1->InsertTuple3(i, 0, 0, 255);
	selectedColors2->InsertTuple3(i, 170, 85, 255);
	selectedColors3->InsertTuple3(i, 170, 170, 255);
	selectedColors4->InsertTuple3(i, 170, 170, 0);
	selectedColors5->InsertTuple3(i, 255, 85, 255);
	selectedColors6->InsertTuple3(i, 85, 170, 255);
	selectedColors7->InsertTuple3(i, 85, 85, 255);
	selectedColors8->InsertTuple3(i, 255, 170, 0);
	selectedColors9->InsertTuple3(i, 255, 0, 127);

	data->SetPoints(points);
	data->SetLines(line);
	data->GetPointData()->AddArray(tuberad);
	data->GetPointData()->SetActiveScalars("tuberad");
	data->GetPointData()->AddArray(normalColors);
	data->GetPointData()->AddArray(selectedColors0);
	data->GetPointData()->AddArray(selectedColors1);
	data->GetPointData()->AddArray(selectedColors2);
	data->GetPointData()->AddArray(selectedColors3);
	data->GetPointData()->AddArray(selectedColors4);
	data->GetPointData()->AddArray(selectedColors5);
	data->GetPointData()->AddArray(selectedColors6);
	data->GetPointData()->AddArray(selectedColors7);
	data->GetPointData()->AddArray(selectedColors8);
	data->GetPointData()->AddArray(selectedColors9);


	vtkTubeFilter *tube = vtkTubeFilter::New();
	tube->SetInput(data);
	tube->SetVaryRadiusToVaryRadiusByAbsoluteScalar(); 
	tube->SetNumberOfSides( 16 );
	tube->Update();

	vtkPolyDataMapper *tubesMapper = vtkPolyDataMapper::New();
	tubesMapper->SetInput(tube->GetOutput());
	tubesMapper->SetScalarModeToUsePointFieldData();
	if ( maxradius+0.2 >= minradius)
		tubesMapper->SelectColorArray("normalColors");  
	else
		tubesMapper->SelectColorArray("selectedColors9");
	tubesMapper->Update();

	vtkActor *actor = vtkActor::New();
	actor->SetMapper(tubesMapper);

	m_displayFramework->getActive3DView()->getRenderer()->AddActor(actor);
	//m_displayFramework->getActive3DView()->render();

// 	m_listBranchVolumeData.push_back(pointlist);
// 	m_listBranchData.push_back(data);
// 	m_listBranchTube.push_back(tube);
// 	m_listBranchMapper.push_back(tubesMapper);
// 	m_listBranchActor.push_back(actor);
// 	m_listBranchID.push_back(QPair<int,int>(nid,bid));

	branchInfo->listBranchVolumeData = pointlist;
	branchInfo->polyData = data;
	branchInfo->tubeFilter = tube;
	branchInfo->polyDataMapper = tubesMapper;
	branchInfo->actor = actor;
	branchInfo->branchID = QPair<int,int>(nid, bid);
	m_listBranchInfo.push_back(branchInfo);
}

QPair<int,int> DisplayModel::getBranchID(vtkActor* actor)
{
	for(int i = 0; i < m_listBranchInfo.count(); i++)
	{
		if ( actor == m_listBranchInfo[i]->actor)
			return m_listBranchInfo[i]->branchID;
	}

	return QPair<int,int>();
}

bool DisplayModel::isABranch( vtkActor *actor )
{
	for(int i = 0; i < m_listBranchInfo.count(); i++)
	{
		if ( actor == m_listBranchInfo[i]->actor)
			return true;
	}
	return false;
}

void DisplayModel::removeABranch(int nid, int bid)
{
	int i = 0;
	QList<BranchInfo_t*>::iterator it = m_listBranchInfo.begin();

	for(; it != m_listBranchInfo.end();)
	{
		if ((*it)->branchID.first == nid &&	(*it)->branchID.second == bid)
		{
			m_displayFramework->getActive3DView()->getRenderer()->RemoveActor((*it)->actor);
			//m_listBranchInfo[i]->actor->SetVisibility(0);
 			(*it)->polyData->Delete();
 			(*it)->tubeFilter->Delete();
 			(*it)->polyDataMapper->Delete();
 			(*it)->actor->Delete();
			it = m_listBranchInfo.erase(it);
		}
		else
			it++;
	}


	m_listSelectedBranchActor.clear();
	m_listSelectedIndics.clear();

	m_displayFramework->getActive3DView()->render();
}

void DisplayModel::removeABranch(vtkActor* actor, bool allChildren /*=true*/)
{
	QList<BranchInfo_t*> readyToRemove;
	QStack<QPair<QVector4D, QVector4D>> selectedBranch;
	m_listSelectedBranchActor.clear();

	for(int i = 0; i < m_listBranchInfo.count(); i++)
	{
		if ( actor == m_listBranchInfo[i]->actor)
		{
			selectedBranch.push(m_listBranchInfo[i]->pairStartEnds);
			readyToRemove.push_back(m_listBranchInfo[i]);
		}
	}

	if ( allChildren)
	{
		while (1)
		{
			if ( selectedBranch.count()== 0)
				break;

			QPair<QVector4D, QVector4D> currentBranch = selectedBranch.pop();

			for (int i = 0; i < m_listBranchInfo.count(); i++)
			{
				if ( currentBranch.second == m_listBranchInfo[i]->pairStartEnds.first)
				{
					selectedBranch.push(m_listBranchInfo[i]->pairStartEnds);
					readyToRemove.push_back(m_listBranchInfo[i]);
				}
			}
		}
	}


	QList<BranchInfo_t*>::iterator it = readyToRemove.begin();
	for (; it != readyToRemove.end(); it++)
	{
		removeABranch((*it)->branchID.first, (*it)->branchID.second);
	}

	m_displayFramework->getActive3DView()->render();
}

QList<QList<QVector4D>> DisplayModel::getSelectedBranch()
{
	QList<QList<QVector4D>> selectedBranches;
	if ( m_selectedIndex != -1)
	{
		for (int i = 0; i < m_listSelectedIndics.count(); i++)
		{
			selectedBranches.push_back(m_listBranchInfo[m_listSelectedIndics.at(i)]->listBranchVolumeData);
		}
	}
	return selectedBranches;
}


void DisplayModel::removeRebuiltBranches()
{
	m_selectedIndex = -1;

	for(int i = 0; i < m_listBranchInfo.count(); i++)
	{
		m_displayFramework->getActive3DView()->getRenderer()->RemoveActor(m_listBranchInfo[i]->actor);
		m_listBranchInfo[i]->polyData->Delete();
		m_listBranchInfo[i]->tubeFilter->Delete();
		m_listBranchInfo[i]->polyDataMapper->Delete();
		m_listBranchInfo[i]->actor->Delete();
	}

	m_listSelectedIndics.clear();
	m_listSelectedBranchActor.clear();
	m_listBranchInfo.clear();

	m_displayFramework->getActive3DView()->render();
}

void DisplayModel::clearSelectedBranches()
{
	for(int i = 0; i < m_listBranchInfo.count(); i++)
	{
		m_listBranchInfo[i]->polyDataMapper->SelectColorArray("normalColors");
	}

	m_listSelectedBranchActor.clear();
	m_listSelectedIndics.clear();

	m_displayFramework->getActive3DView()->render();
}


void DisplayModel::setSelectABranch(QList<QVector4D> branch, int color /*=0*/)
{
	for (int i = 0; i < m_listBranchInfo.count(); i++)
	{
		if (branch.at(0) == m_listBranchInfo[i]->listBranchVolumeData.at(0) &&
			branch.at(1) == m_listBranchInfo[i]->listBranchVolumeData.at(1) &&
			branch.at(2) == m_listBranchInfo[i]->listBranchVolumeData.at(2))
		{
			setSelectABranch(m_listBranchInfo[i]->actor, true, color);
			return;
		}
	}
}





void DisplayModel::setBranchClass(int bclass, QVector4D startnode, QVector4D endnode)
{
	for (int i = 0; i < m_listBranchInfo.count(); i++)
	{
		if ( m_listBranchInfo[i]->pairStartEnds.second.x() == endnode.x() && 
			 m_listBranchInfo[i]->pairStartEnds.second.y() == endnode.y() && 
			 m_listBranchInfo[i]->pairStartEnds.second.z() == endnode.z() )
		{
			setSelectABranch(m_listBranchInfo[i]->actor, true, bclass);
		}
	}
}


void DisplayModel::setSelectABranch( vtkActor* actor, bool selected, int color /*=0*/ )
{
	QStack<QPair<QVector4D, QVector4D>> selectedBranch;

	for(int i = 0; i < m_listBranchInfo.count(); i++)
	{
		if ( actor == m_listBranchInfo[i]->actor)
		{
			selectedBranch.push(m_listBranchInfo[i]->pairStartEnds);

			if ( color == 0)
			{
				cout << "selected a branch" << endl;
				cout << " branch length : " << m_listBranchInfo[i]->listBranchVolumeData.count() << endl;
				cout << " sampled length : " << m_listBranchInfo[i]->polyData->GetPoints()->GetNumberOfPoints() << endl;
			}

			if ( selected == true)
			{
				char colorstr[30]={0};
				sprintf(colorstr, "selectedColors%d", color);
				m_listBranchInfo[i]->polyDataMapper->SelectColorArray(colorstr);
				m_listSelectedBranchActor.push(m_listBranchInfo[i]->actor);
				m_listSelectedIndics.push_back(i);
				m_selectedIndex = i;
			}
			else
			{
				m_listBranchInfo[i]->polyDataMapper->SelectColorArray("normalColors");
				for (int j = 0; j < m_listSelectedBranchActor.count(); i++)
				{
					if ( m_listSelectedBranchActor.at(j) == actor)
					{
						m_listSelectedBranchActor.remove(j);
						m_listSelectedIndics.remove(i);
						break;
					}
				}
			}
		}
	}


	while (1)
	{
		if ( selectedBranch.count()== 0)
			break;

		QPair<QVector4D, QVector4D> currentBranch = selectedBranch.pop();

		for (int i = 0; i < m_listBranchInfo.count(); i++)
		{
			if ( currentBranch.second == m_listBranchInfo[i]->pairStartEnds.first)
			{
				selectedBranch.push(m_listBranchInfo[i]->pairStartEnds);

				if ( selected == true)
				{
					char colorstr[20];
					sprintf(colorstr, "selectedColors%d", color);
					m_listBranchInfo[i]->polyDataMapper->SelectColorArray(colorstr);
					m_listSelectedBranchActor.push(m_listBranchInfo[i]->actor);
				}
				else
				{
					m_listBranchInfo[i]->polyDataMapper->SelectColorArray("normalColors");
					for (int j = 0; j < m_listSelectedBranchActor.count(); i++)
					{
						if ( m_listSelectedBranchActor.at(j) == m_listBranchInfo[i]->actor)
						{
							m_listSelectedBranchActor.remove(j);
							break;
						}
					}
				}
			}
		}
	}

	cout << " children : " << m_listSelectedBranchActor.count() -1 << endl;

	m_displayFramework->getActive3DView()->render();
}

void DisplayModel::addActor( vtkActor* actor )
{
	m_displayFramework->getActive3DView()->addProper(actor);
}



